import { EventListener } from "./libs/EventListener";
import { Renderer } from "./renderer";
import { Scene } from "./scene";
import { NormalizeTheta } from './utils/NormalizeTheta';

//
export function VrPanoramic(container, props = {}) {

    // 正北偏移角度
    this.compassOffset = 0;
    // 场景大小半径
    this.sceneRadius = 100;
    //
    this.logoSize = 20;

    //
    // merge objects
    this.mergeObjects(props);


    /**
     * container
     * */
    this.container = typeof container === 'object' ? container : document.getElementById(container);
    this.container.classList.add('vr-panoramic-container');


    /**
     * renderer
     * */
    this.renderer = new Renderer(this.container);
    this.renderer.camera.position.z = this.sceneRadius * 0.5;


    /**
     * scene
     * */
    this.scenes = [
        new Scene(this.renderer, { sphereSize: this.sceneRadius, logoSize: this.logoSize }),
        new Scene(this.renderer, { sphereSize: this.sceneRadius, logoSize: this.logoSize })
    ];

    //
    this.scenes.forEach(scene => {
        //
        scene.controls.on('update', object => {
            //
            const { x, y, z } = object.rotation;
            //
            let phi = -(180 / Math.PI * x);
            let roll = 180 / Math.PI * y;
            let theta = 180 / Math.PI * z % 360;
            if (theta < 0) theta += 360;
            //
            this.emit('rotate', { phi, roll, theta });
        });
    })

    // bind click
    this.renderer.domElement.addEventListener('click', event => {
        //
        const vector3 = this.renderer.pointToVector3(event.layerX, event.layerY);
        //
        if (vector3) event.vector3 = vector3;
        //
        this.emit('click', event);

    }, false);


    // resize
    this.resize = () => {
        //
        this.renderer.resize(this.container.clientWidth, this.container.clientHeight);
        return this;
    }

    // add
    this.add = (object) => {
        //
        const index = this.sceneIndex || 0;
        //
        this.scenes[index].add(object);
        //
        return this;
    };

    // remove
    this.remove = (object) => {
        //
        this.scenes.forEach(scene => {
            //
            let index = scene.children.findIndex(mesh => mesh === object);
            //
            if (index > -1) {
                scene.children.splice(index, 1);
            }
        });
        return this;
    };

    // clear
    this.clear = () => {
        this.clearPanoramic().clearLogo();
        return this;
    };

    // Activate
    this.activate = () => {
        this.renderer.ENABLED = true;
        return this;
    }

    // Deactivate
    this.deactivate = () => {
        this.renderer.ENABLED = false;
        return this;
    }

    // animateTo
    this.animateTo = (props = {}) => {
        //
        const index = this.sceneIndex || 0;
        //
        const scene = this.scenes[index];

        // end
        const start = {
            theta: scene.rotation.z,
            phi: scene.rotation.x
        };
        // end
        const end = {};
        // center
        if (props.center !== undefined) {
            // euler
            const euler = this.renderer.vector3ToEulerAngle(props.center);
            // phi
            end.phi = -(euler.phi * (Math.PI / 180));
            // theta
            end.theta = euler.theta * (Math.PI / 180);
        }
        // phi | theta
        else {
            if (props.phi !== undefined) {
                end.phi = -(props.phi * (Math.PI / 180));
            }
            if (props.theta !== undefined) {
                end.theta = props.theta * (Math.PI / 180);
            }
        }

        // theta
        end.theta = NormalizeTheta(end.theta, start.theta);

        // 限制
        if (Math.abs(end.theta - start.theta) < 0.000001 && Math.abs(end.phi - start.phi) < 0.000001) return;
        // animate
        scene.controls.animate({ theta: [start.theta, end.theta], phi: [start.phi, end.phi] }, props.duration || 1000, res => {
            scene.controls.update(res.phi, 0, res.theta);
        });

    };


    // pointToVector3
    this.pointToVector3 = (x, y) => {
        return this.renderer.pointToVector3(x, y);
    };


    // vector3ToEulerAngle
    this.vector3ToEulerAngle = (x, y, z) => {
        return this.renderer.vector3ToEulerAngle(x, y);
    };


    // 获取欧拉角
    this.getEulerAngle = () => {
        //
        let index = this.sceneIndex || 0;
        //
        let { x, y, z } = this.scenes[index].rotation;
        //
        let phi = -(180 / Math.PI * x);
        let roll = 180 / Math.PI * y;
        let theta = 180 / Math.PI * z % 360;
        if (theta < 0) theta += 360;

        return {
            phi,
            roll,
            theta
        }
    };

    //
    this.toDataURL = (format = "image/jpeg") => {
        return this.renderer.renderer.domElement.toDataURL(format);
    };


    // 加载全景图
    this.loadPanoramic = (() => {
        // 纹理暂存
        const __TEXTURES__ = {};
        //
        const __LOADER__ = new THREE.TextureLoader();
        //
        return (url, props = {}) => {

            return new Promise((resolve, reject) => {
                //
                let current, next, index = this.scenes.findIndex(scene => scene.visible);
                //
                if (index > -1) {
                    //
                    this.sceneIndex = (index + 1) % this.scenes.length;
                    //
                    current = this.scenes[index];
                    next = this.scenes[this.sceneIndex];
                }
                else {
                    //
                    this.sceneIndex = 0;
                    //
                    current = this.scenes[this.scenes.length - 1];
                    next = this.scenes[0];
                }

                // 加载完成
                const complete = (texture) => {
                    // 切换下一个
                    next.loadPanoramic(texture).show(200);
                    // 隐藏当前
                    current.hide(500);

                    // 停止自动旋转
                    current.autoplay.stop();
                    next.autoplay.stop();

                    // 水平旋转
                    let theta = props.theta || 0;
                    // 倾斜旋转
                    let phi = props.phi || 90;
                    //
                    if (theta || phi) {
                        //
                        next.controls.update(-phi * Math.PI / 180, 0, theta * Math.PI / 180);
                    }

                    // 自动水平旋转
                    if (props.autoplay) {
                        // speed
                        let speed = typeof props.autoplay === 'number' ? props.autoplay : null;
                        if (typeof props.autoplay === 'object') speed = props.autoplay.speed || speed;
                        //
                        next.autoplay.update(speed).start();
                    }
                    //
                    resolve();
                }

                // load texture
                let texture = __TEXTURES__[url];
                if (!texture) {
                    __LOADER__.load(url, (texture) => complete(__TEXTURES__[url] = texture), () => { }, reject);
                }
                else {
                    complete(texture);
                }

            });
        }

    })();

    // 加载Logo
    this.loadLogo = (() => {

        // 纹理暂存
        const __TEXTURES__ = {};
        //
        const __LOADER__ = new THREE.TextureLoader();
        //
        return (url, props = {}) => {

            // complete
            const complete = (texture) => {
                this.scenes.forEach(scene => {
                    scene.loadLogo(texture);
                });
            }

            // load texture
            let texture = __TEXTURES__[url];
            if (!texture) {
                __LOADER__.load(url, (texture) => complete(__TEXTURES__[url] = texture));
            }
            else {
                complete(texture);
            }
        }

    })();

    // clearPanoramic
    this.clearPanoramic = () => {
        this.scenes.forEach(scene => {
            scene.clearPanoramic();
        });
        return this;
    };

    // clearLogo
    this.clearLogo = () => {
        this.scenes.forEach(scene => {
            scene.clearLogo();
        });
        return this;
    };

    //


    // bind resize
    window.addEventListener('resize', () => this.resize(), false);
}


// prototype
VrPanoramic.prototype = Object.assign(VrPanoramic.prototype, EventListener.prototype);
VrPanoramic.prototype.constructor = VrPanoramic;